import { Modal, Select } from 'antd';
import React, { useMemo, useState } from 'react';
import { NodeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import CollapsibleSection from '@/components/CollapsibleSection';
import CodeEditor from '@/components/Textarea/CodeEditor';
import { t } from '@/locales/i18n';
import { FlowNodeOutputTypeEnum, NodeInputKeyEnum } from '@/types/workflow/constant';
import { FlowNodeInputItemType } from '@/types/workflow/io';
import { FlowNodeItemType } from '@/types/workflow/node';
import {
  JS_TEMPLATE,
  SandboxCodeTypeEnum,
  SNADBOX_CODE_TEMPLATE,
} from '@/types/workflow/template/system/sandbox/constants';

import { WorkflowContext } from '../../context';

import NodeCard from './render/NodeCard';
import RenderInput from './render/RenderInput';
import RenderOutput from './render/RenderOutput';

const NodeCode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
  const [expandedSections, setExpandedSections] = useState<Set<'output' | 'input' | 'params'>>(
    new Set(['input']),
  );
  const [isConfirmOpen, setIsConfirmOpen] = useState(false);

  const toggleSection = (section: 'output' | 'input' | 'params') => {
    setExpandedSections((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(section)) {
        newSet.delete(section);
      } else {
        newSet.add(section);
      }
      return newSet;
    });
  };
  const { nodeId, inputs, outputs } = data;
  const codeType = inputs.find(
    (item) => item.key === NodeInputKeyEnum.codeType,
  ) as FlowNodeInputItemType;
  const { splitToolInputs, onChangeNode, onResetNode } = useContextSelector(
    WorkflowContext,
    (ctx) => ctx,
  );

  const handleConfirm = () => {
    const code = inputs.find((item) => item.key === NodeInputKeyEnum.code);
    code &&
      onChangeNode({
        nodeId,
        type: 'updateInput',
        key: 'code',
        value: {
          ...code,
          value: JS_TEMPLATE,
        },
      });
    setIsConfirmOpen(false);
  };

  const CustomComponent = useMemo(() => {
    return {
      [NodeInputKeyEnum.code]: (item: FlowNodeInputItemType) => {
        return (
          <div>
            <div className="mb-1 flex items-end">
              <div className="flex-1">
                {' '}
                <Select
                  options={[
                    { label: 'JavaScript', value: SandboxCodeTypeEnum.js },
                    { label: 'Python 3', value: SandboxCodeTypeEnum.py },
                  ]}
                  value={codeType?.value}
                  onChange={(newLang) => {
                    onChangeNode({
                      nodeId,
                      type: 'updateInput',
                      key: NodeInputKeyEnum.codeType,
                      value: { ...codeType, value: newLang },
                    });

                    onChangeNode({
                      nodeId,
                      type: 'updateInput',
                      key: item.key,
                      value: {
                        ...item,
                        value:
                          SNADBOX_CODE_TEMPLATE[
                            newLang as unknown as keyof typeof SNADBOX_CODE_TEMPLATE
                          ],
                      },
                    });
                  }}
                />
              </div>
              <div
                className="cursor-pointer text-xs text-primary"
                onClick={() => setIsConfirmOpen(true)}
              >
                {t('code.Reset template')}
              </div>
            </div>
            <CodeEditor
              language={codeType.value}
              className="nodrag rounded-sm bg-white"
              value={item.value}
              onChange={(e) => {
                onChangeNode({
                  nodeId,
                  type: 'updateInput',
                  key: item.key,
                  value: {
                    ...item,
                    value: e,
                  },
                });
              }}
            />
          </div>
        );
      },
    };
  }, [codeType, nodeId, onChangeNode]);

  const Render = useMemo(() => {
    const { isTool, commonInputs } = splitToolInputs(inputs, nodeId);

    const filterHiddenInputs = commonInputs.filter((item) => true);

    return (
      <NodeCard minW="400px" selected={selected} {...data}>
        <div className="flex flex-col gap-3 space-y-0">
          <CollapsibleSection
            title="运行参数配置"
            subtitle="配置代码运行的引用参数及代码"
            isExpanded={expandedSections.has('params')}
            onToggle={() => toggleSection('params')}
            type="params"
          >
            <div className="space-y-2">
              {filterHiddenInputs.length > 0 && (
                <RenderInput
                  nodeId={nodeId}
                  flowInputList={filterHiddenInputs}
                  CustomComponent={CustomComponent}
                />
              )}
            </div>
          </CollapsibleSection>

          <CollapsibleSection
            title={t('workflow.node.output')}
            subtitle={t('workflow.node.output_desc')}
            isExpanded={expandedSections.has('output')}
            onToggle={() => toggleSection('output')}
            type="output"
            className="pb-3"
          >
            {outputs.filter((output) => output.type !== FlowNodeOutputTypeEnum.hidden).length >
              0 && (
              <div className="px-2">
                <RenderOutput nodeId={nodeId} flowOutputList={outputs} />
              </div>
            )}
          </CollapsibleSection>
        </div>
        <Modal
          open={isConfirmOpen}
          title={t('Warning')}
          onCancel={() => setIsConfirmOpen(false)}
          onOk={handleConfirm}
          okText={t('common.Confirm')}
          cancelText={t('common.Cancel')}
        >
          <div className="pt-5 text-sm">{t('code.Reset template confirm')}</div>
        </Modal>
      </NodeCard>
    );
  }, [
    expandedSections,
    CustomComponent,
    data,
    inputs,
    nodeId,
    outputs,
    selected,
    splitToolInputs,
    isConfirmOpen,
    handleConfirm,
  ]);

  return Render;
};
export default React.memo(NodeCode);
